#include "vm.h"

// operand 操作数
// opecode 操作码

static void reverse(char *instr[])
{ // 0号元素挪到数组最后面，其他元素索引-1
    instr[LINE_MAX_SIZE - 1] = instr[0];
    for (int i = 1; i < LINE_MAX_SIZE - 1; i++)
    {
        instr[i - 1] = instr[i];
    }
}

static bool validate(char *instr[])
{ // 检查指令是否合法，同时如果数组第一个元素是label，则挪到最后一个位置上
    bool result = false;
    for (int i = 0; i < INSTRUCTION_SIZE; i++)
    {
        if (strcmp(instr[0], instruction_mapping[i].name) >= 0)
        {
            result = true;
            break;
        }
    }
    return result;
}

// 分割字符串
static void splitLine(char *instr, char *strArr[])
{
    byte i = 0;
    char *buff;

    while (i < LINE_MAX_SIZE) // 清空操作，防止存在垃圾数据
    {
        *strArr[i] = ' ';
        i++;
    }

    i = 0;
    buff = instr;
    strArr[i] = strsep(&buff, " ");
    while (strArr[i] != NULL)
    {
        printf("%s\n", strArr[i]);

        // 判断这个
        strArr[i] = strsep(&buff, " ");
        i++;
    }
    
}

// 判断字符串是否以某个字符串开头
static bool isPrefixWith(char *string, char *prefix)
{
    if (string == NULL || prefix == NULL)
        return false;
    int len1 = strlen(string);
    int len2 = strlen(prefix);
    if ((len1 < len2) || (len1 == 0 || len2 == 0))
        return false;
    char *p = prefix;
    int i = 0;
    while (*p != '\0')
    {
        if (*p != string[i])
            return false;
        p++;
        i++;
    }
    return true;
}

void parserLine(vmState *vm, char *instr)
{
    byte i = 0;
    char *p[LINE_MAX_SIZE] = {0};
    char *buff;

    while (i < LINE_MAX_SIZE) // 清空操作，防止存在垃圾数据
    {
        *p[i] = ' ';
        i++;
    }

    i = 0;
    buff = instr;
    p[i] = strsep(&buff, " ");
    while (p[i] != NULL)
    {
        printf("%s\n", p);
        if (*p[i] != ' ') { // 如果不是空字符串
            if (validate(p) == false)
            { // 将地址和对应索引保存到虚拟机字典中
                vm->maps[vm->map_index]->key = p[i];
                vm->maps[vm->map_index]->value = vm->instruction_index;
                vm->map_index++;
            } else { // 否则认为是指令，将原始指令保存在虚拟机中
                vm->instructions[vm->instruction_index] = p[i];
                vm->instruction_index++;
            }
        }

        // 判断这个
        p[i] = strsep(&buff, " ");
        i++;
    }
}

int getInstruction(vmState *vm, Instruction *result)
{
    int res = -1;
    char *strArr = vm->instructions[vm->instruction_index];
    for (int i = 0; i < INSTRUCTION_SIZE; i++)
    {
        if (strcmp(strArr, instruction_mapping[i].name) >= 0)
        {
            result->name = instruction_mapping[i].name;
            result->instruction = instruction_mapping[i].instruction;
            result->length = instruction_mapping[i].length;
            res = i;
            break;
        }
    }
    return res;
}

void parser(vmState *vm, char *instr, Instruction *result)
{
    char *strArr[LINE_MAX_SIZE];
    splitLine(instr, strArr);
    if (validate(strArr) == false) { // 检查第一遍，是否合法
        // 第一遍不合法，将位置调整后，在此校验
        reverse(strArr);
        // 如果还是非法指令，则直接报错
        if (validate(strArr) == false) {
            printf("Illegal instruction: %s.\n", strArr[0]);
            return;
        } else { // 将地址和对应索引保存到虚拟机字典中
            vm->maps[vm->map_index]->key = strArr[0];
            vm->maps[vm->map_index]->value = vm->instruction_index;
            vm->map_index++;
        }
        // 合法的话，继续向下执行
    }

    // 如果想减少嗲码，可以考虑将下面这个for循环替换成下面这个方法去调用
    // 我个人觉得定义很多变量很恶心，就不写成函数调用方式了

    for (int i = 0; i < INSTRUCTION_SIZE; i++)
    {
        if (strcmp(strArr[0], instruction_mapping[i].name) >= 0)
        {
            result->name = instruction_mapping[i].name;
            result->instruction = instruction_mapping[i].instruction;
            result->length = instruction_mapping[i].length;
            break;
        }
    }
}

// 为了处理跳转指令的情况
// 这里需要定义两个变量
// 一个变量用来保存要跳转的地址，此时由于整体代码还没有解析完成

// 除了主程序外，其他文件代码不得私自使用alloc/malloc/realloc等函数申请空间，否则会造成内存泄漏

void delete_char(char str[], char target)
{
    int i, j;
    for (i = j = 0; str[i] != '\0'; i++)
    {
        if (str[i] != target)
        {
            str[j++] = str[i];
        }
    }
    str[j] = '\0';
}

/**判断str1是否以str2开头
 * 如果是返回1
 * 不是返回0
 * 出错返回-1
 * */
bool is_begin_with(const char *str1, char *str2)
{
    if (str1 == NULL || str2 == NULL)
        return false;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if ((len1 < len2) || (len1 == 0 || len2 == 0))
        return false;
    char *p = str2;
    int i = 0;
    while (*p != '\0')
    {
        if (*p != str1[i])
            return false;
        p++;
        i++;
    }
    return true;
}

/**判断str1是否以str2结尾
 * 如果是返回1
 * 不是返回0
 * 出错返回-1
 * */
int is_end_with(const char *str1, char *str2)
{
    if (str1 == NULL || str2 == NULL)
        return false;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if ((len1 < len2) || (len1 == 0 || len2 == 0))
        return false;
    while (len2 >= 1)
    {
        if (str2[len2 - 1] != str1[len1 - 1])
            return false;
        len2--;
        len1--;
    }
    return true;
}